package edu.gatech.cs2340.spring2012.team38.contentprovider;

import java.util.Arrays;
import java.util.HashSet;

import edu.gatech.cs2340.spring2012.team38.database.UserDBHelper;
import edu.gatech.cs2340.spring2012.team38.database.UserTable;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class UserContentProvider extends ContentProvider {
	
	private UserDBHelper database;
	
	// Used for the UriMatcher
	private static final int USERS = 10;
	private static final int USER_ID = 20;
	
	private static final String AUTHORITY = "edu.gatech.cs2340.spring2012.contentprovider";

	private static final String BASE_PATH = "users";
	public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
			+ "/" + BASE_PATH);

	public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE
			+ "/todos";
	public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE
			+ "/todo";

	private static final UriMatcher sURIMatcher = new UriMatcher(
			UriMatcher.NO_MATCH);
	static {
		sURIMatcher.addURI(AUTHORITY, BASE_PATH, USERS);
		sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", USER_ID);
	}
	
	// TODO : THIS FUCKING DOC
	/**
	 * Deletes a row. Or something. More on this later...
	 * @param uri Points to the database probably
	 * @param selection What you want to delete
	 * @param selectionArgs I don't know. How to delete the rows?
	 * @return Number of rows deleted.
	 */
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int uriType = sURIMatcher.match(uri);
		SQLiteDatabase sqlDB = database.getWritableDatabase();
		int rowsDeleted = 0;
		switch (uriType) {
		case USERS:
			rowsDeleted = sqlDB.delete(UserTable.TABLE_USERS, selection,
					selectionArgs);
			break;
		case USER_ID:
			String id = uri.getLastPathSegment();
			if (TextUtils.isEmpty(selection)) {
				rowsDeleted = sqlDB.delete(
						UserTable.TABLE_USERS,
						UserTable.COLUMN_ID + "=" + id, 
						null);
			} else {
				rowsDeleted = sqlDB.delete(
						UserTable.TABLE_USERS,
						UserTable.COLUMN_ID + "=" + id 
						+ " and " + selection,
						selectionArgs);
			}
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return rowsDeleted;
	}

	/**
	 * Nothing, lol.
	 */
	@Override
	public String getType(Uri uri) {
		return null;
	}

	/**
	 * Inserts values into a uri
	 * @param uri The best I can tell, some sort of address for the database.
	 * @param values Probably the values to insert. I'll need to fix 
	 * these docs later...
	 * @return A URI pointing to the id of the new row
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values) {
		int uriType = sURIMatcher.match(uri);
		SQLiteDatabase sqlDB = database.getWritableDatabase();
		long id = 0;
		switch (uriType) {
		case USERS:
			id = sqlDB.insert(UserTable.TABLE_USERS, null, values);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return Uri.parse(BASE_PATH + "/" + id);
	}

	/**
	 * Creates a db.
	 * @return T/F on db creation.
	 */
	@Override
	public boolean onCreate() {
		database = new UserDBHelper(getContext());
		return false; // I don't think we'll need this return value(neither
					  // did a tutorial I looked at). Assume db is always 
					  // created I guess.
	}
	
	/**
	 * Returns a cursor when it gets a query from the db
	 * @param uri DB "address"
	 * @param projection It uh...
	 * @param selection The query
	 * @param selectionArgs MFW I don't even...
	 * @param sortOrder The order of the sorting for the returned rows
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// Using SQLiteQueryBuilder instead of query() method
		SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

		// Check if the caller has requested a column which does not exists
		checkColumns(projection);

		// Set the table
		queryBuilder.setTables(UserTable.TABLE_USERS);

		int uriType = sURIMatcher.match(uri);
		switch (uriType) {
		case USERS:
			break;
		case USER_ID:
			// Adding the ID to the original query
			queryBuilder.appendWhere(UserTable.COLUMN_ID + "="
					+ uri.getLastPathSegment());
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}

		SQLiteDatabase db = database.getWritableDatabase();
		Cursor cursor = queryBuilder.query(db, projection, selection,
				selectionArgs, null, null, sortOrder);
		// Make sure that potential listeners are getting notified
		cursor.setNotificationUri(getContext().getContentResolver(), uri);

		return cursor;
	}

	/**
	 * Updates a row in the db. 
	 * @param uri Address of the db
	 * @param values The um, 
	 * @param selection The part you want to update. Or a query for that.
	 * @param selectionArgs 
	 * @return The number of rows updated
	 */
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		
		int uriType = sURIMatcher.match(uri);
		SQLiteDatabase sqlDB = database.getWritableDatabase();
		int rowsUpdated = 0;
		switch (uriType) {
		case USERS:
			rowsUpdated = sqlDB.update(UserTable.TABLE_USERS, 
					values, 
					selection,
					selectionArgs);
			break;
		case USER_ID:
			String id = uri.getLastPathSegment();
			if (TextUtils.isEmpty(selection)) {
				rowsUpdated = sqlDB.update(UserTable.TABLE_USERS, 
						values,
						UserTable.COLUMN_ID + "=" + id, 
						null);
			} else {
				rowsUpdated = sqlDB.update(UserTable.TABLE_USERS, 
						values,
						UserTable.COLUMN_ID + "=" + id 
						+ " and " 
						+ selection,
						selectionArgs);
			}
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return rowsUpdated;
	}
	
	/**
	 * Checks to make sure the requested columns exist. Used above.
	 * @param projection
	 */
	private void checkColumns(String[] projection) {
		String[] available = { UserTable.COLUMN_GROUP,
				UserTable.COLUMN_USERNAME, UserTable.COLUMN_PASSWORD,
				UserTable.COLUMN_ID };
		if (projection != null) {
			HashSet<String> requestedColumns = new HashSet<String>(
					Arrays.asList(projection));
			HashSet<String> availableColumns = new HashSet<String>(
					Arrays.asList(available));
			// Check if all columns which are requested are available
			if (!availableColumns.containsAll(requestedColumns)) {
				throw new IllegalArgumentException(
						"Unknown columns in projection");
			}
		}
	}

	
}
